---
title: 战术板
subTitle: grid-layout 样式应用实例
---
<template>
  <div class="" style="margin:0 auto; width:350px;">
    <div class="ground">
      <div class="warp container" ref="container">
        <div :class="{'position': true, 'fl': true, 'active': draging && !players.FL} " ><my-drop class="drop-place"  @drop="handleDrop('FL', ...arguments)" @enter="handleEnter('FL', ...arguments)" enter-class="enter"  @leave="switchPosId = ''"> FL </my-drop></div>
        <div :class="{'position': true, 'fc': true, 'active': draging && !players.FC} " ><my-drop class="drop-place" @drop="handleDrop('FC', ...arguments)" @enter="handleEnter('FC', ...arguments)" enter-class="enter"  @leave="switchPosId = ''"> FC </my-drop></div>
        <div :class="{'position': true, 'fr': true, 'active': draging && !players.FR} " ><my-drop class="drop-place" @drop="handleDrop('FR', ...arguments)" @enter="handleEnter('FR', ...arguments)" enter-class="enter" @leave="switchPosId = ''">FR</my-drop></div>

        <div :class="{'position': true, 'wl': true, 'active': draging && !players.WL} "><my-drop class="drop-place" @drop="handleDrop('WL', ...arguments)"  @enter="handleEnter('WL', ...arguments)" enter-class="enter" @leave="switchPosId = ''">WL</my-drop></div>
        <div :class="{'position': true, 'amcl': true, 'active': draging && !players.AMCL} "><my-drop class="drop-place" @drop="handleDrop('AMCL', ...arguments) " @enter="handleEnter('AMCL', ...arguments)" enter-class="enter" @leave="switchPosId = ''">AMCL</my-drop></div>
        <div :class="{'position': true, 'amc': true, 'active': draging && !players.AMC}"><my-drop class="drop-place" @drop="handleDrop('AMC', ...arguments)" @enter="handleEnter('AMC', ...arguments)" enter-class="enter" @leave="switchPosId = ''">AMC</my-drop></div>
        <div :class="{'position': true, 'amcr': true, 'active': draging && !players.AMCR} "><my-drop class="drop-place" @drop="handleDrop('AMCR', ...arguments)" @enter="handleEnter('AMCR', ...arguments)" enter-class="enter" @leave="switchPosId = ''">AMCR</my-drop></div>
        <div :class="{'position': true, 'wr': true, 'active': draging && !players.WR} "><my-drop class="drop-place" @drop="handleDrop('WR', ...arguments)" @enter="handleEnter('WR', ...arguments)" enter-class="enter" @leave="switchPosId = ''">WR</my-drop></div>

        <div :class="{'position': true, 'ml': true, 'active': draging && !players.ML} "><my-drop class="drop-place" @drop="handleDrop('ML', ...arguments)" @enter="handleEnter('ML', ...arguments)" enter-class="enter" @leave="switchPosId = ''">ML</my-drop></div>
        <div :class="{'position': true, 'mcl': true, 'active': draging && !players.MCL} "><my-drop class="drop-place" @drop="handleDrop('MCL', ...arguments)" @enter="handleEnter('MCL', ...arguments)" enter-class="enter" @leave="switchPosId = ''">MCL</my-drop></div>
        <div :class="{'position': true, 'mc': true, 'active': draging && !players.MC} "><my-drop class="drop-place" @drop="handleDrop('MC', ...arguments)" @enter="handleEnter('MC', ...arguments)" enter-class="enter" @leave="switchPosId = ''">MC</my-drop></div>
        <div :class="{'position': true, 'mcr': true, 'active': draging && !players.MCR} "><my-drop class="drop-place" @drop="handleDrop('MCR', ...arguments)" @enter="handleEnter('MCR', ...arguments)" enter-class="enter" @leave="switchPosId = ''">MCR</my-drop></div>
        <div :class="{'position': true, 'mr': true, 'active': draging && !players.MR} "><my-drop class="drop-place" @drop="handleDrop('MR', ...arguments)" @enter="handleEnter('MR', ...arguments)" enter-class="enter" @leave="switchPosId = ''">MR</my-drop></div>

        <div :class="{'position': true, 'wbl': true, 'active': draging && !players.WBL} "><my-drop class="drop-place" @drop="handleDrop('WBL', ...arguments)" @enter="handleEnter('WBL', ...arguments)" enter-class="enter" @leave="switchPosId = ''">WBL</my-drop></div>
        <div :class="{'position': true, 'dmcl': true, 'active': draging && !players.DMCL} "><my-drop class="drop-place" @drop="handleDrop('DMCL', ...arguments)" @enter="handleEnter('DMCL', ...arguments)" enter-class="enter" @leave="switchPosId = ''">DMCL</my-drop></div>
        <div :class="{'position': true, 'dmc': true, 'active': draging && !players.DMC} "><my-drop class="drop-place" @drop="handleDrop('DMC', ...arguments)" @enter="handleEnter('DMC', ...arguments)" enter-class="enter" @leave="switchPosId = ''">DMC</my-drop></div>
        <div :class="{'position': true, 'dmcr': true, 'active': draging && !players.DMCR} "><my-drop class="drop-place" @drop="handleDrop('DMCR', ...arguments)" @enter="handleEnter('DMCR', ...arguments)" enter-class="enter" @leave="switchPosId = ''">DMCR</my-drop></div>
        <div :class="{'position': true, 'wbr': true, 'active': draging && !players.WBR} "><my-drop class="drop-place" @drop="handleDrop('WBR', ...arguments)" @enter="handleEnter('WBR', ...arguments)" enter-class="enter" @leave="switchPosId = ''">WBR</my-drop></div>

        <div :class="{'position': true, 'dl': true, 'active': draging && !players.DL} "><my-drop class="drop-place" @drop="handleDrop('DL', ...arguments)" @enter="handleEnter('DL', ...arguments)" enter-class="enter" @leave="switchPosId = ''">DL</my-drop></div>
        <div :class="{'position': true, 'dcl': true, 'active': draging && !players.DCL} "><my-drop class="drop-place" @drop="handleDrop('DCL', ...arguments)" @enter="handleEnter('DCL', ...arguments)" enter-class="enter" @leave="switchPosId = ''">DCL</my-drop></div>
        <div :class="{'position': true, 'dc': true, 'active': draging && !players.DC} "><my-drop class="drop-place" @drop="handleDrop('DC', ...arguments)" @enter="handleEnter('DC', ...arguments)" enter-class="enter" @leave="switchPosId = ''">DC</my-drop></div>
        <div :class="{'position': true, 'dcr': true, 'active': draging && !players.DCR} "><my-drop class="drop-place" @drop="handleDrop('DCR', ...arguments)" @enter="handleEnter('DCR', ...arguments)" enter-class="enter" @leave="switchPosId = ''">DCR</my-drop></div>
        <div :class="{'position': true, 'dr': true, 'active': draging && !players.DR} "><my-drop class="drop-place" @drop="handleDrop('DR', ...arguments)" @enter="handleEnter('DR', ...arguments)" enter-class="enter" @leave="switchPosId = ''">DR</my-drop></div>

        <div :class="{'position': true, 'gk': true, 'active': draging && !players.GK} "><my-drop class="drop-place" @drop="handleDrop('GK', ...arguments)" @enter="handleEnter('GK', ...arguments)" enter-class="enter" @leave="switchPosId = ''">GK</my-drop></div>

        <my-drag clone revert v-for="(value, key) in players" :style="{
          'position': 'absolute',
          'left': value.pos.left + 'px',
          'top': value.pos.top + 'px',
          'width': value.pos.width + 'px',
          'height': value.pos.height + 'px'
        }" :key="`player_${key}`" @drag="dragHandle(value, ...arguments)">
          <div :class="{'player': true, 'is-drag': draging, 'is-switch': switchPosId === key}">
            
            <div class="logo-warp">
              <div class="number-warp">{{value.data.num}}</div>
            </div>
            <div class="role-warp">
              
            </div>
            <div class="name-warp">
              {{value.data.name}}
            </div>
            
          </div> 

        </my-drag>
      </div>
    </div>
  </div>
</template>
<style lang="scss" scoped>
.ground{
  box-sizing: border-box;
  position: relative;
  width: 100%;
  height:0;
  padding-top: 150%;
  * {
    box-sizing: border-box;
  }
  background-image: url('../../../../assets/tactic/ground.jpg');
  background-size: contain;
  .warp{
    position: absolute;
    width:100%;
    top: 0;
    bottom: 0;
    // background: red;
    &.container{
      padding: 25px 20px 10px 20px;
      display:grid;
      grid-template:
        [froward-start] ". FL FC FR ." auto [froward-end]
        [midfield-a-start] "WL AMCL AMC AMCR WR" auto [midfield-a-end]
        [midfield-start] "ML MCL MC MCR MR" auto [midfield-end]
        [midfield-d-start] "WBL DMCL DMC DMCR WBR" auto [midfield-d-end]
        [defense-start] "DL DCL DC DCR DR" auto [defense-end]
        [goalkeep-start] ". . GK . ." auto [goalkeep-start]
        / calc(20% - 4px) calc(20% - 4px) calc(20% - 4px) calc(20% - 4px); 
      grid-gap: 10px 5px;  
      .fr{ grid-area: FR; }
      .fc { grid-area: FC; }
      .fl { grid-area: FL; }
      .wl { grid-area: WL; }
      .amcl { grid-area: AMCL; } 
      .amc { grid-area: AMC; }
      .amcr { grid-area: AMCR; }
      .wr{ grid-area: WR; }
      .ml { grid-area: ML; }
      .mcl { grid-area: MCL; }
      .mc { grid-area: MC; }
      .mcr { grid-area: MCR; }
      .mr { grid-area: MR; }
      .wbl { grid-area: WBL; }
      .dmcl { grid-area: DMCL; }
      .dmc { grid-area: DMC; }
      .dmcr { grid-area: DMCR; }
      .wbr { grid-area: WBR; }
      .dl { grid-area: DL; }
      .dcl { grid-area: DCL; } 
      .dc { grid-area: DC; }
      .dcr { grid-area: DCR; } 
      .dr { grid-area: DR; }
      .gk { grid-area: GK; }
      .position{ 
        opacity: 0;
        text-align: center;
        color: white;
        font-size: 1.2em;
        line-height: 1.4;
        font-weight: 800;
        background: rgba(255, 255, 255, 0.5);
        &.active{
          opacity: 1; 
        }
        .drop-place{
          width: 100%;
          height:100%;
          &.enter{
            background: rgba(225, 225, 0, .7);
          }
        }
      } 

      .player{
        // position: absolute;
        width: 100%;
        height:100%;
        padding-top:5px; 
        .logo-warp{
          position:relative;
          width: 70%;
          height: 0;
          padding-top: 60%;
          margin: 0 auto;
          background: no-repeat;
          background-image: url('../../../../assets/tactic/player.png');
          background-size: 90% auto;
          background-position: center center; 
          .number-warp{
            position: absolute;
            width: 100%;
            top: 25%;
            text-align:center;
            color: white;
            font-size: 1em;
            font-weight: 700;
            
          }
        }
        .role-warp, .name-warp{
          text-align: center;
          line-height: 1.2;
        }
        &.is-drag{
          pointer-events: none;
          opacity: 0.3;
        }
        &.is-switch{
          opacity: 1;
          // background:green;
          background: rgba(225, 120, 0, 0.6);
          .logo-warp {
            background-image: url('../../../../assets/tactic/player-red.png');
          }
        }
      }
    }
  }
}
</style>
<script>
const FourFourTwo = [
  { posId: 'GK', data: {name: '球员a', num: '1'} }, 
  { posId: 'DL', data: {name: '球员b', num: '2'} }, 
  { posId: 'DCL', data: {name: '球员c', num: '3'} }, 
  { posId: 'DCR', data: {name: '球员d', num: '4'} }, 
  { posId: 'DR', data: {name: '球员e', num: '5'} }, 
  { posId: 'ML', data: {name: '球员f', num: '7'} }, 
  { posId: 'MCL', data: {name: '球员g', num: '6'} }, 
  { posId: 'MCR', data: {name: '球员h', num: '10'} }, 
  { posId: 'MR', data: {name: '球员i', num: '8'} }, 
  { posId: 'FL', data: {name: '球员j', num: '11'} }, 
  { posId: 'FR', data: {name: '球员k', num: '9'} }
]
const MakeCenterClose = function(pMap) {
  const rate = 0.3
  if (!pMap.FC) {
    if (pMap.FL) {
      pMap.FL.pos.left = pMap.FL.pos.left + pMap.FL.pos.width * rate 
    }
    if (pMap.FR) {
      pMap.FR.pos.left = pMap.FR.pos.left - pMap.FR.pos.width * rate
    } 
  }
  if (!pMap.AMC) {
    if (pMap.AMCL) {
      pMap.AMCL.pos.left = pMap.AMCL.pos.left + pMap.AMCL.pos.width * rate 
    }
    if (pMap.AMCR) {
      pMap.AMCR.pos.left = pMap.AMCR.pos.left - pMap.AMCR.pos.width * rate
    } 
  }
  if (!pMap.MC) {
    if (pMap.MCL) {
      pMap.MCL.pos.left = pMap.MCL.pos.left + pMap.MCL.pos.width * rate 
    }
    if (pMap.MCR) {
      pMap.MCR.pos.left = pMap.MCR.pos.left - pMap.MCR.pos.width * rate
    } 
  }
  if (!pMap.DMC) {
    if (pMap.DMCL) {
      pMap.DMCL.pos.left = pMap.DMCL.pos.left + pMap.DMCL.pos.width * rate 
    }
    if (pMap.DMCR) {
      pMap.DMCR.pos.left = pMap.DMCR.pos.left - pMap.DMCR.pos.width * rate
    } 
  }
  if (!pMap.DC) {
    if (pMap.DCL) {
      pMap.DCL.pos.left = pMap.DCL.pos.left + pMap.DCL.pos.width * rate 
    }
    if (pMap.DCR) {
      pMap.DCR.pos.left = pMap.DCR.pos.left - pMap.DCR.pos.width * rate
    } 
  } 
}

export default {
  components: {},
  props: {
  },
  data() {
    return {
      allPosData: {},
      playerData: [...FourFourTwo], // {}

      players: {},

      draging: false,
      dragPlayer: null,
      switchPosId: ''
    }
  },
  computed: {
    
  },
  methods: {
    calcAllPosData() { 
      const allPos = this.$refs.container.querySelectorAll('.position')
    
      const pos = Array.from(allPos).reduce((total, node) => {
        total[node.className.split(' ')[1].toUpperCase()] = {
          pos: {
            top: node.offsetTop,
            left: node.offsetLeft,
            width: node.offsetWidth,
            height: node.offsetHeight
          },
          posName: node.className.split(' ')[1],
          posId: node.className.split(' ')[1].toUpperCase()
        }  
        return total
      }, {})
       
      this.allPosData = pos

      this.playersInit()
    },
    playersInit() {
      const pMap = this.playerData.reduce((total, item) => {
        const target = JSON.parse(JSON.stringify(this.allPosData[item.posId]))
        total[item.posId] = { ...target, data: item.data} 
        return total
      }, {})
      MakeCenterClose(pMap)
      // console.log(pMap) 
      this.players = pMap
    },
     
   
    
    dragHandle(player) {
      this.draging = true
      if (!this.dragPlayer) {
        this.dragPlayer = player
      }
      // console.log(player)
    },
    handleDrop(posId) { 
      const dragPosId = this.dragPlayer.posId
      const dropPosId = posId 
      
      if (this.players[dropPosId]) { // 交换位置
         
        const dropPlayerData = this.players[dropPosId].data
        const dragPlayerData = this.players[dragPosId].data

        this.$set(this.players[dropPosId], 'data', dragPlayerData)
        this.$set(this.players[dragPosId], 'data', dropPlayerData)

      } else { 
        const players = {...this.players}
        players[dropPosId] = null
        const dragPlayerData = players[dragPosId].data
        delete players[dragPosId]
        Object.keys(players).forEach((key) => {
          if (players[key]) {
            const data = players[key].data
            players[key] = {...JSON.parse(JSON.stringify(this.allPosData[key])), data: data}
          } else {
            players[key] = {...JSON.parse(JSON.stringify(this.allPosData[key])), data: dragPlayerData}
          }
           
        }) 
        MakeCenterClose(players)
        // console.log('players', players)
        this.players = players
      }
      this.$nextTick(() => { 
        this.draging = false
        this.dragPlayer = null
        this.switchPosId = ''
      })
      
    },
    handleEnter(posId) {
      console.log('enter', arguments)
      this.switchPosId = posId
    }
  },
  created() {
  },
  mounted() {
    setTimeout(() => {
      this.calcAllPosData()
    }, 300) 
  }
}
</script>
